﻿/*
 * Module Name: HelperClass.cs
 * 
 * Purpose: This class is used to store commonly used functions
 * 
 * Created by: Chris Tisdale
 */

using System;
using System.Collections.Generic;
using System.Threading;
using System.IO;

namespace Common_Code.Heler_Functions
{
    public static class HelperClass
    {
        /*
         * Name: Swap
         * 
         * Parameters: T v
         *             T w
         * 
         * Returns: If v is less than w
         * 
         * Purpose: This functions will tell if v is less than w
         */
        public static bool Less<T>(T v, T w)
        {
            return (String.Compare((v.ToString()), w.ToString(), StringComparison.Ordinal) < 0);
        }

        /*
         * Name: eq
         * 
         * Parameters: T v
         *             T w
         * 
         * Returns: If the items are equal
         * 
         * Purpose: This functions will determine if two items are equal
         */
// ReSharper disable once InconsistentNaming
        public static bool eq<T>(T v, T w)
        {
            return (String.Compare((v.ToString()), w.ToString(), StringComparison.Ordinal) == 0);
        }

        /*
         * Name: Swap
         * 
         * Parameters: T ils
         *             T rhs
         * 
         * Returns: NA
         * 
         * Purpose: This functions is used to move a opject from one type to another
         */
        public static void Swap<T>(ref T lhs, ref T rhs)
        {
            var temp = lhs;
            lhs = rhs;
            rhs = temp;
        }

        /*
         * Name: Swap
         * 
         * Parameters: T ils
         *             T rhs
         * 
         * Returns: NA
         * 
         * Purpose: This functions is used to move a object from one type to another
         */
        public static void Swap<T>(ref T[] lis, int element1, int element2)
        {
            var temp = lis[element1];
            lis[element1] = lis[element2];
            lis[element2] = temp;
        }

        /*
         * Name: ReadFile
         * 
         * Parameters: string fileName
         * 
         * Returns: IEnumerable<string>
         * 
         * Purpose:  Allows you to traverse a files lines
         */
        public static IEnumerable<string> ReadFile(string fileName)
        {
            var sr = new StreamReader(fileName);
            String line;
            while ((line = sr.ReadLine()) != null)
            {
                yield return line;
            }
            sr.Close();
        }

        /*
         * Name: WriteToFile
         * 
         * Parameters: string fileName
         *             IEnumerable<string> thingsToWrite
         * 
         * Returns: None
         * 
         * Purpose:  Allows you to add lines to any file
         */
        public static void WriteToFile<T>(string fileName, List<T> thingsToWrite)
        {
            var sw = new StreamWriter(fileName);
            try
            {
                foreach (var item in thingsToWrite)
                {
                    sw.WriteLine(item);
                }
            }
// ReSharper disable once EmptyGeneralCatchClause
            catch { }
            sw.Close();
        }

        /*
         * Name: DegreesToRad
         * 
         * Parameters: double degree
         * 
         * Returns: double radians
         * 
         * Purpose:  Converts Degrees to Radians
         */
        public static double DegreesToRad(double degree)
        {
            return (degree * 180) / Math.PI;
        }

        /*
         * Name: RadToDegrees
         * 
         * Parameters: double rad
         * 
         * Returns: double degrees
         * 
         * Purpose:  Converts Degrees to Radians
         */
        public static double RadToDegrees(double rad)
        {
            return (rad * Math.PI) / 180;
        }

        /*
         * Name: QuickSort
         * 
         * Parameters: T[] lis
         *             int lo, int hi
         * 
         * Returns: None
         * 
         * Purpose: Allows you to sort any list
         */
#if OLD_CODE
        public static T[] QuickSort<T>(T[] lis)
        {
            T[] tempL = new T[lis.Length];
            T[] tempR = new T[lis.Length];
            int Rcount = 0;
            int Lcount = 0;
            T var = lis[(lis.Length - 1)];
            string piv = var.ToString();
            int comp = 0;
            for (int i = 0; i < (lis.Length - 1); i++)
            {
                comp = piv.CompareTo((lis[i]).ToString());
                if (comp > 0)
                    tempL[Lcount++] = lis[i];
                else if (comp < 0)
                    tempR[Rcount++] = lis[i];
                else { }
                    //tempR.Add(lis.ElementAt<T>(i));
            }
            tempL = QuickSort(tempL);
            //tempL.AddRange(QuickSort(tempR));
            return tempL;
        }
#else
/*************************************************************************
 *  Compilation:  javac Quick3way.java
 *  Execution:    java Quick3way < input.txt
 *  Dependencies: StdOut.java StdIn.java
 *  Data files:   http://algs4.cs.princeton.edu/23quicksort/tiny.txt
 *                http://algs4.cs.princeton.edu/23quicksort/words3.txt
 *   
 *  Sorts a sequence of strings from standard input using 3-way quicksort.
 *   
 *  % more tiny.txt
 *  S O R T E X A M P L E
 *
 *  % java Quick3way < tiny.txt
 *  A E E L M O P R S T X                 [ one string per line ]
 *    
 *  % more words3.txt
 *  bed bug dad yes zoo ... all bad yet
 *  
 *  % java Quick3way < words3.txt
 *  all bad bed bug dad ... yes yet zoo    [ one string per line ]
 *
 * This was ported to C#
 *************************************************************************/
        public static void QuickSort<T>(ref T[] lis, int lo, int hi)
        {
            if (hi <= lo)
                return;
            int lt = lo, gt = hi;
            var v = lis[lo];
            var i = lo;
            while (i <= gt)
            {
                if (Less(lis[i], v))
                    Swap(ref lis, lt++, i++);
                else if (Less(v, lis[i]))
                    Swap(ref lis, i, gt--);
                else
                    i++;
            }
            QuickSort(ref lis, lo, lt - 1);
            QuickSort(ref lis, gt + 1, hi);
        }
#endif

        /*
         * Name: HeapSort
         * 
         * Parameters: T[] lis
         * 
         * Returns: T[]
         * 
         * Purpose:  Allows you to sort any list
         */
        public static T[] HeapSort<T>(T[] lis)
        {
            throw new NotImplementedException();
        }

        /*
         * Name: MergeSort
         * 
         * Parameters: T[] lis
         * 
         * Returns: T[]
         * 
         * Purpose:  Allows you to sort any list
         */
        public static T[] MergeSort<T>(T[] lis)
        {
            throw new NotImplementedException();
        }

        /*
         * Name: BubbleSort
         * 
         * Parameters: T[] lis
         * 
         * Returns: None
         * 
         * Purpose:  Allows you to sort any list
         */
        public static void BubbleSort<T>(ref T[] lis)
        {
            var j = 0;
            var swapped = true;
            while (swapped)
            {
                swapped = false;
                j++;
                for (var i = 0; i < (lis.Length - j); i++)
                {
                    if (!Less(lis[i + 1], lis[i]))
                        continue;
                    Swap(ref lis[i], ref lis[i + 1]);
                    swapped = true;
                }
            }
        }

        /*
         * Name: ShellSort
         * 
         * Parameters: T[] lis
         * 
         * Returns: T[]
         * 
         * Purpose:  Allows you to sort any list
         */
        public static T[] ShellSort<T>(T[] lis)
        {
            throw new NotImplementedException();
        }

        /*
         * Name: SelectionSort
         * 
         * Parameters: T[] lis
         * 
         * Returns: T[]
         * 
         * Purpose:  Allows you to sort any list
         */
        public static T[] SelectionSort<T>(T[] lis)
        {
            throw new NotImplementedException();
        }

        /*
         * Name: InsertionSort
         * 
         * Parameters: T[] lis
         * 
         * Returns: T[]
         * 
         * Purpose:  Allows you to sort any list
         */
        public static T[] InsertionSort<T>(T[] lis)
        {
            throw new NotImplementedException();
        }

        /*
         * Name: PlaceItemAtLoc
         * 
         * Parameters: T[] lis
         *             T val
         *             int loc
         * 
         * Returns: T[]
         * 
         * Purpose:  Places item in array at loc and shifts the array
         */
        public static T[] PlaceItemAtLoc<T>(T[] lis, T val, int loc)
        {
            if (lis == null)
                throw new NotSupportedException("Cannot have a null array");
            var temp = new T[lis.Length + 1];
            if (lis.Length == 0)
                temp[0] = val;
            else
            {
                var count = 0;
                for (var i = 0; i < (lis.Length); i++)
                {
                    if (i == loc)
                        temp[i] = val;
                    else
                    {
                        temp[i] = lis[count];
                        count++;
                    }
                }
            }
            return temp;
        }

        /*
         * Name: BinarySearch
         * 
         * Parmeters: T array
         *            T element
         * 
         * Returns: Int
         * 
         * Purpose: This funtion seaches the array for the element and returns the index.
         *          If the element is not found -1 is returned
         */
        public static int BinarySearch<T>(T[] array, T element)
        {
            var count = array.Length / 2;
            var found = false;
            var top = array.Length;
            while (!found)
            {
                var temp = array[count];
                var comp = String.Compare(temp.ToString(), element.ToString(), StringComparison.Ordinal);
                if (comp == 0)
                    found = true;
                else if (comp < 0)
                    count = (top + count) / 2;
                else
                {
                    top = count;
                    count = count / 2;
                }
                if (count == 0)
                {
                    return -1;
                }
            }
            return count;
        }

        /*
         * Name: LinearSearch
         * 
         * Parmeters: T array
         *            T element
         * 
         * Returns: Int
         * 
         * Purpose: This funtion seaches the array for the element and returns the index.
         *          If the element is not found -1 is returned
         */
        public static int LinearSearch<T>(T[] array, T element)
        {
            var loc = -1;
            for (var i = 0; i < (array.Length - 1); i++)
            {
                if (String.Compare(array[i].ToString(), element.ToString(), StringComparison.Ordinal) != 0)
                    continue;
                i = array.Length;
                loc = i;
            }
            return loc;
        }

        /*
         * Name: SplitAndKeep
         * 
         * Parmeters: string s
         *            char[] delims
         * 
         * Returns: IEnumerable<String>
         * 
         * Purpose: This functions is used to split a string with the given delims
         *          and keep the orginal string still intact
         */
        public static IEnumerable<string> SplitAndKeep(this string s, char[] delims)
        {
            var start = 0;
            int index;

            while ((index = s.IndexOfAny(delims, start)) != -1)
            {
                index++;
                index = Interlocked.Exchange(ref start, index);

                yield return s.Substring(index, start - index - 1);
                yield return s.Substring(start - 1, 1);
            }

            if (start < s.Length)
            {
                yield return s.Substring(start);
            }
        }

        /*
         * Name: B64_length
         * 
         * Parameters: IntPtr len
         * 
         * Returns: IntPrt
         * 
         * Purpose: This function is used to get the proper length for the Base64 encyrption algorithm
         */
        public static IntPtr B64_length(IntPtr len)
        {
            IntPtr ret;
            if(Environment.Is64BitOperatingSystem) //64 Bit Operating system
            {
                var npad = len.ToInt64() % 3;
                Int64 size;
                if(npad > 0)
                {
                    size = len.ToInt64() + 3 - npad;
                }
                else
                {
                    size = len.ToInt64();
                }
                ret = new IntPtr((size * 8) / 6);
            }
            else //32 Bit Operating system
            {
                var npad = len.ToInt32() % 3;
                Int32 size;
                if(npad > 0)
                {
                    size = len.ToInt32() + 3 - npad;
                }
                else
                {
                    size = len.ToInt32();
                }
                ret = new IntPtr((size * 8) / 6);
            }
            return ret;
        }

        /*
         * Name: Ascii_length
         * 
         * Parameters: IntPtr len
         * 
         * Returns: IntPrt
         * 
         * Purpose: This function is used to get the proper Ascii length for the Base64 encyrption algorithm
         */
        public static IntPtr Ascii_length(IntPtr len)
        {
            return Environment.Is64BitOperatingSystem ? new IntPtr((len.ToInt64() * 6) / 8) : new IntPtr((len.ToInt32() * 6) / 8);
        }
    }
}
